-
Notifications
You must be signed in to change notification settings - Fork 92
add tron support for smart contracts and payment processor #1684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
add tron support for smart contracts and payment processor #1684
Conversation
WalkthroughAdds comprehensive TRON support: chain definitions, TRC20/ERC20FeeProxy smart contracts, deployment/migration tooling, payment-processor Tron utilities, payment-detection (The Graph + detector), a Substreams module for indexing, tests, and CI workflow for Tron artifacts. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client App
participant TronWeb as TronWeb
participant Proxy as ERC20FeeProxy
participant Token as TRC20 Token
Client->>TronWeb: getAllowance(token, owner, proxy)
TronWeb->>Token: allowance(owner, proxy)
Token-->>TronWeb: allowanceAmount
TronWeb-->>Client: allowanceAmount
alt Allowance insufficient
Client->>TronWeb: approve(token, proxy, amount)
TronWeb->>Token: approve(proxy, amount)
Token-->>TronWeb: txHash
TronWeb-->>Client: txHash
end
Client->>TronWeb: call transferFromWithReferenceAndFee(proxy, token, from, to, amount, ref, fee, feeAddress)
TronWeb->>Proxy: transferFromWithReferenceAndFee(...)
Proxy->>Token: transferFrom(from, proxy, total)
Token-->>Proxy: success/fail
Proxy->>Token: transfer(to, paymentAmount)
Token-->>Proxy: success
Proxy->>Token: transfer(feeAddress, feeAmount)
Token-->>Proxy: success
Proxy-->>TronWeb: event TransferWithReferenceAndFee
TronWeb-->>Client: txHash / receipt
sequenceDiagram
participant Substreams as Substreams Module
participant Block as Block data
participant Parser as map_erc20_fee_proxy_payments
participant TheGraph as TheGraph/publisher
participant Detector as TronERC20FeeProxyPaymentDetector
participant Client as Client App
Substreams->>Block: read block
Substreams->>Parser: inspect tx logs
Parser->>Parser: filter by proxy addresses & parse events
Parser-->>TheGraph: emit Payment entities
TheGraph-->>TheGraph: index payments
Client->>Detector: request detection(reference, to, token, network)
Detector->>TheGraph: query GetTronPayments(reference, to, token, contract)
TheGraph-->>Detector: payments[]
Detector->>Client: mapped TronPaymentEvent[]
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
1946425 to
74afb66
Compare
Greptile SummaryThis PR adds comprehensive Tron blockchain support to Request Network, enabling TRC20 token payments through the Key Changes
Implementation QualityThe implementation demonstrates strong engineering practices:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User as User/Payer
participant TronWeb as TronWeb
participant PaymentProcessor as Payment Processor
participant TRC20 as TRC20 Token
participant FeeProxy as ERC20FeeProxy Contract
participant Payee as Payment Recipient
participant FeeRecipient as Fee Recipient
User->>PaymentProcessor: payTronFeeProxyRequest(request, tronWeb)
PaymentProcessor->>PaymentProcessor: validateRequest()
PaymentProcessor->>PaymentProcessor: getTronPaymentInfo()
Note over PaymentProcessor: Check allowance and balance
PaymentProcessor->>TronWeb: getTronAllowance(tokenAddress, network)
TronWeb->>TRC20: allowance(payer, proxyAddress)
TRC20-->>TronWeb: currentAllowance
TronWeb-->>PaymentProcessor: currentAllowance
alt Insufficient Allowance
PaymentProcessor-->>User: Error: Insufficient allowance
User->>PaymentProcessor: approveTronFeeProxyRequest(request, tronWeb)
PaymentProcessor->>TronWeb: approveTrc20(tokenAddress, network, amount)
TronWeb->>TRC20: approve(proxyAddress, amount)
TRC20-->>TronWeb: txHash
TronWeb-->>PaymentProcessor: txHash
PaymentProcessor-->>User: Approval txHash
end
PaymentProcessor->>TronWeb: isTronAccountSolvent(tokenAddress, totalAmount)
TronWeb->>TRC20: balanceOf(payer)
TRC20-->>TronWeb: balance
TronWeb-->>PaymentProcessor: hasSufficientBalance
alt Insufficient Balance
PaymentProcessor-->>User: Error: Insufficient balance
end
Note over PaymentProcessor: Process payment
PaymentProcessor->>TronWeb: processTronFeeProxyPayment()
TronWeb->>FeeProxy: transferFromWithReferenceAndFee(tokenAddress, payee, amount, reference, feeAmount, feeAddress)
Note over FeeProxy: Execute transfers
FeeProxy->>TRC20: transferFrom(payer, payee, amount)
TRC20->>Payee: Transfer payment amount
TRC20-->>FeeProxy: success
alt Fee Amount > 0
FeeProxy->>TRC20: transferFrom(payer, feeRecipient, feeAmount)
TRC20->>FeeRecipient: Transfer fee amount
TRC20-->>FeeProxy: success
end
FeeProxy->>FeeProxy: emit TransferWithReferenceAndFee()
FeeProxy-->>TronWeb: txHash
TronWeb-->>PaymentProcessor: txHash
PaymentProcessor-->>User: Payment txHash
|
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
74afb66 to
bfd7e2f
Compare
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
bfd7e2f to
bf7961e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/smart-contracts/tron/deployments/mainnet.json`:
- Around line 8-11: The ERC20FeeProxy entry currently has hexAddress set to
"TO_BE_FILLED"; update the ERC20FeeProxy object so hexAddress contains the
correct Tron hex address (the 41... format) that corresponds to address
"TCUDPYnS9dH3WvFEaE7wN7vnDa51J4R4fd", or if that field is unused remove the
hexAddress key entirely; locate the ERC20FeeProxy block in the JSON (the object
with "address", "hexAddress", "creationBlockNumber") and either replace
"TO_BE_FILLED" with the actual 41-prefixed hex address or delete the hexAddress
property to avoid runtime resolution failures.
In `@packages/smart-contracts/tron/deployments/nile.json`:
- Around line 9-11: Replace the incorrect hexAddress value for the deployment
entry that has address "THK5rNmrvCujhmrXa5DB1dASepwXTr9cJs": update the
"hexAddress" field from "414b8e0e0d4c9ec8a8f3f4a5b6c7d8e9f0a1b2c3d4" to the
correct hex derived from the base58 address —
"41508B3B4059C40BB3AAC5DA5AC006CCDD9C4DC957" so the JSON entry's "hexAddress"
matches the "address" and prevents runtime contract interaction failures.
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
bf7961e to
a990789
Compare
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
6ff88e8 to
5d88414
Compare
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
1 similar comment
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
1 similar comment
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
5d88414 to
7c8c1e3
Compare
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
7c8c1e3 to
eb28e46
Compare
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
… importing files from outside its configured contracts_directory. I replaced the re-export approach with a full copy of the ERC20FeeProxy contract in the tron directory. I added a comment noting that this is a copy maintained for TronBox compatibility.
eb28e46 to
87a95a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@packages/smart-contracts/scripts/tron/deploy-mainnet.js`:
- Around line 167-168: The deploy script currently writes the mainnet manifest
to the scripts' local deployments folder causing the canonical package-level
manifest to go stale; update the outputPath construction (the path.join call
that sets outputPath used by fs.writeFileSync) so it targets the package-level
deployments/tron mainnet manifest (i.e., the package deployments/tron
mainnet.json) instead of the scripts/deployments folder, ensuring deploymentInfo
is written to the canonical file used by tooling.
In `@packages/smart-contracts/scripts/tron/deploy-nile.js`:
- Around line 133-135: The code builds outputPath with path.join to
'../deployments/…' which resolves to the scripts/deployments folder; change the
join target to point to the tron/deployments directory instead so the JSON lands
under tron/deployments (update the path passed to path.join in the outputPath
assignment). Apply the same change in the other script; keep the surrounding
logic (fs.mkdirSync(path.dirname(outputPath), { recursive: true }) and
fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2))) intact.
Ensure you update the path in both files where outputPath is defined (look for
the symbol outputPath and uses of path.join, fs.mkdirSync, and
fs.writeFileSync).
In `@packages/substreams-tron/proto/payments.proto`:
- Around line 3-44: The proto package declaration "package request.tron.v1" in
this file does not match its current repository directory, causing Buf's
PACKAGE_DIRECTORY_MATCH lint to fail; fix by either moving this proto file into
a directory path that matches the package (request/tron/v1 relative to the repo
root or Buf workspace) or by changing the package declaration to reflect the
file's directory layout, and then re-run buf lint to confirm; refer to the
package line ("package request.tron.v1;") and the messages Payment and Payments
when locating the proto to update or relocate.
In `@packages/substreams-tron/src/lib.rs`:
- Around line 17-47: The map_erc20_fee_proxy_payments handler currently skips
only empty topics and never validates the event signature; update it to first
ensure log_entry.topics[0] exists and matches the expected keccak256 event
signature by comparing a normalized hex string of log_entry.topics[0] to a
corrected TRANSFER_WITH_REF_AND_FEE_TOPIC constant (replace the truncated
40-hex-char value with the full 64-hex-char keccak256 hash and use
lowercase/no-0x normalization), and only proceed parsing when they match;
reference TRANSFER_WITH_REF_AND_FEE_TOPIC, map_erc20_fee_proxy_payments, and
log_entry.topics for where to add this check.
| const outputPath = path.join(__dirname, '../deployments/nile.json'); | ||
| fs.mkdirSync(path.dirname(outputPath), { recursive: true }); | ||
| fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Write deployment JSON to tron/deployments (current path resolves to scripts/deployments).
Line 133 writes to ../deployments/nile.json, which places the file under packages/smart-contracts/scripts/deployments instead of packages/smart-contracts/tron/deployments expected by tooling. Please update this path here and apply the same correction in packages/smart-contracts/scripts/tron/deploy-test-token.js Line 107.
🛠️ Proposed fix
- const outputPath = path.join(__dirname, '../deployments/nile.json');
+ const outputPath = path.join(__dirname, '../../tron/deployments/nile.json');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const outputPath = path.join(__dirname, '../deployments/nile.json'); | |
| fs.mkdirSync(path.dirname(outputPath), { recursive: true }); | |
| fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2)); | |
| const outputPath = path.join(__dirname, '../../tron/deployments/nile.json'); | |
| fs.mkdirSync(path.dirname(outputPath), { recursive: true }); | |
| fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2)); |
🤖 Prompt for AI Agents
In `@packages/smart-contracts/scripts/tron/deploy-nile.js` around lines 133 - 135,
The code builds outputPath with path.join to '../deployments/…' which resolves
to the scripts/deployments folder; change the join target to point to the
tron/deployments directory instead so the JSON lands under tron/deployments
(update the path passed to path.join in the outputPath assignment). Apply the
same change in the other script; keep the surrounding logic
(fs.mkdirSync(path.dirname(outputPath), { recursive: true }) and
fs.writeFileSync(outputPath, JSON.stringify(deploymentInfo, null, 2))) intact.
Ensure you update the path in both files where outputPath is defined (look for
the symbol outputPath and uses of path.join, fs.mkdirSync, and
fs.writeFileSync).
| package request.tron.v1; | ||
|
|
||
| // A single payment event from the ERC20FeeProxy contract | ||
| message Payment { | ||
| // The token contract address (TRC20) | ||
| string token_address = 1; | ||
|
|
||
| // The recipient address | ||
| string to = 2; | ||
|
|
||
| // The payment amount (as string to preserve precision) | ||
| string amount = 3; | ||
|
|
||
| // The indexed payment reference (hex encoded) | ||
| string payment_reference = 4; | ||
|
|
||
| // The fee amount (as string to preserve precision) | ||
| string fee_amount = 5; | ||
|
|
||
| // The fee recipient address | ||
| string fee_address = 6; | ||
|
|
||
| // The sender address (msg.sender) | ||
| string from = 7; | ||
|
|
||
| // Block number where the event was emitted | ||
| uint64 block = 8; | ||
|
|
||
| // Block timestamp (Unix timestamp in seconds) | ||
| uint64 timestamp = 9; | ||
|
|
||
| // Transaction hash | ||
| string tx_hash = 10; | ||
|
|
||
| // The proxy contract address that emitted the event | ||
| string contract_address = 11; | ||
| } | ||
|
|
||
| // Collection of payment events | ||
| message Payments { | ||
| repeated Payment payments = 1; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix proto package directory mismatch (Buf lint failure).
Line 3 declares package request.tron.v1, but the file lives under packages/substreams-tron/proto. If Buf lint is enforced (PACKAGE_DIRECTORY_MATCH), this will fail CI/build. Move the file to request/tron/v1 (relative to repo root or buf workspace), or update the buf configuration to relax/override the rule.
🧰 Tools
🪛 Buf (1.63.0)
3-3: Files with package "request.tron.v1" must be within a directory "request/tron/v1" relative to root but were in directory "packages/substreams-tron/proto".
(PACKAGE_DIRECTORY_MATCH)
🤖 Prompt for AI Agents
In `@packages/substreams-tron/proto/payments.proto` around lines 3 - 44, The proto
package declaration "package request.tron.v1" in this file does not match its
current repository directory, causing Buf's PACKAGE_DIRECTORY_MATCH lint to
fail; fix by either moving this proto file into a directory path that matches
the package (request/tron/v1 relative to the repo root or Buf workspace) or by
changing the package declaration to reflect the file's directory layout, and
then re-run buf lint to confirm; refer to the package line ("package
request.tron.v1;") and the messages Payment and Payments when locating the proto
to update or relocate.
| /// TransferWithReferenceAndFee event signature (keccak256 hash of event signature) | ||
| /// Event: TransferWithReferenceAndFee(address,address,uint256,bytes indexed,uint256,address) | ||
| const TRANSFER_WITH_REF_AND_FEE_TOPIC: &str = | ||
| "e8e8ca0a945b88ee72ec3e1e5f1e9c8f2a0a1e8a"; | ||
|
|
||
| /// Maps TRON blocks to extract ERC20FeeProxy payment events | ||
| #[substreams::handlers::map] | ||
| fn map_erc20_fee_proxy_payments(block: Block) -> Result<Payments, substreams::errors::Error> { | ||
| let mut payments = Vec::new(); | ||
| let block_number = block.number; | ||
| let block_timestamp = block.header.as_ref().map(|h| h.timestamp).unwrap_or(0) / 1000; // Convert from ms to seconds | ||
|
|
||
| for transaction in block.transactions.iter() { | ||
| let tx_hash = hex::encode(&transaction.txid); | ||
|
|
||
| // Get the transaction result to access logs | ||
| if let Some(result) = &transaction.result { | ||
| for log_entry in result.logs.iter() { | ||
| // Check if this log is from one of our proxy contracts | ||
| let contract_address = base58_encode(&log_entry.address); | ||
|
|
||
| if contract_address != MAINNET_PROXY_ADDRESS | ||
| && contract_address != NILE_PROXY_ADDRESS { | ||
| continue; | ||
| } | ||
|
|
||
| // Check if this is a TransferWithReferenceAndFee event | ||
| // The first topic should be the event signature | ||
| if log_entry.topics.is_empty() { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, check if the TRON substreams directory exists
find . -type d -name "*tron*" | head -20Repository: RequestNetwork/requestNetwork
Length of output: 515
🏁 Script executed:
# List files in packages directory
ls -la packages/ 2>/dev/null | head -20Repository: RequestNetwork/requestNetwork
Length of output: 1268
🏁 Script executed:
# Search for substreams-tron or any TRON-related files
fd -t f "lib.rs" | grep -i tronRepository: RequestNetwork/requestNetwork
Length of output: 108
🏁 Script executed:
# Broader search for any TRON references
rg -l "tron" --max-count=20 -iRepository: RequestNetwork/requestNetwork
Length of output: 3486
🏁 Script executed:
# Read the lib.rs file to verify the claims
cat -n packages/substreams-tron/src/lib.rs | head -150Repository: RequestNetwork/requestNetwork
Length of output: 6371
🏁 Script executed:
# Search for any usage of TRANSFER_WITH_REF_AND_FEE_TOPIC in the codebase
rg "TRANSFER_WITH_REF_AND_FEE_TOPIC" -nRepository: RequestNetwork/requestNetwork
Length of output: 157
🏁 Script executed:
# Let me verify the keccak256 hash for the event signature
# Need to find out what the correct hash should be
rg -A5 -B5 "TransferWithReferenceAndFee" packages/substreams-tron/Repository: RequestNetwork/requestNetwork
Length of output: 6202
🏁 Script executed:
# Check the smart contract definition to get the exact event signature
rg -n "TransferWithReferenceAndFee" packages/smart-contracts/Repository: RequestNetwork/requestNetwork
Length of output: 12984
🏁 Script executed:
# Let's also check if there are any tests for the substreams-tron module
find packages/substreams-tron -name "*.test.*" -o -name "*.spec.*"Repository: RequestNetwork/requestNetwork
Length of output: 55
🏁 Script executed:
# Let's search for keccak256 or event hash references in TRON-related files
rg -i "keccak256\|event.*hash\|topic" packages/smart-contracts/src/contracts/tron/ -A 2 -B 2Repository: RequestNetwork/requestNetwork
Length of output: 55
🏁 Script executed:
# Read the TRON ERC20FeeProxy contract to see the exact event definition
cat packages/smart-contracts/src/contracts/tron/ERC20FeeProxy.solRepository: RequestNetwork/requestNetwork
Length of output: 294
🏁 Script executed:
# Let's check if there are any tools or scripts that compute keccak256 hashes
find . -name "*.py" -o -name "*.js" -o -name "*.ts" | xargs grep -l "keccak256" | head -10Repository: RequestNetwork/requestNetwork
Length of output: 733
🏁 Script executed:
# Let's use Python to calculate the correct keccak256 hash for the event
python3 << 'EOF'
import hashlib
# The event signature as described in the code
event_sig = "TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)"
print(f"Event signature: {event_sig}")
# Calculate keccak256 hash
# Note: We need to use Web3 or similar, but let's try with hashlib first
# For now, let's just show what we know
print(f"Expected hash length: 64 hex chars (32 bytes)")
print(f"Current value length: 40 hex chars (20 bytes)")
print(f"Current value: e8e8ca0a945b88ee72ec3e1e5f1e9c8f2a0a1e8a")
# Try to install web3 to calculate the actual hash
EOFRepository: RequestNetwork/requestNetwork
Length of output: 312
🏁 Script executed:
# Let's try to find if there's a calculation or reference in test files
rg "e8e8ca0a945b88ee72ec3e1e5f1e9c8f2a0a1e8a" -A2 -B2Repository: RequestNetwork/requestNetwork
Length of output: 502
🏁 Script executed:
# Read the complete lib.rs file to see if the constant is ever compared
cat -n packages/substreams-tron/src/lib.rs | grep -A 30 "if log_entry.topics.is_empty"Repository: RequestNetwork/requestNetwork
Length of output: 1224
🏁 Script executed:
# Read the parse function to see if there's any validation happening
cat -n packages/substreams-tron/src/lib.rs | sed -n '67,135p'Repository: RequestNetwork/requestNetwork
Length of output: 2794
🏁 Script executed:
# Let's calculate the correct keccak256 hash using web3 if available
python3 << 'EOF'
# Try different approaches to get the keccak256 hash
import subprocess
import sys
# First, check if web3 is available
try:
from web3 import Web3
event_sig = "TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)"
keccak_hash = Web3.keccak(text=event_sig)
print(f"Correct keccak256 hash: {keccak_hash.hex()}")
except ImportError:
print("web3 not available, installing...")
subprocess.run([sys.executable, "-m", "pip", "install", "web3", "-q"])
from web3 import Web3
event_sig = "TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)"
keccak_hash = Web3.keccak(text=event_sig)
print(f"Correct keccak256 hash: {keccak_hash.hex()}")
EOFRepository: RequestNetwork/requestNetwork
Length of output: 643
🏁 Script executed:
# Try using Node.js to calculate keccak256 hash
node << 'EOF'
// Try using built-in crypto (though it's SHA-3, not keccak256)
// Let's install and use ethers.js instead
const cp = require('child_process');
console.log("Installing ethers.js...");
cp.execSync('npm install -g ethers --no-save', {stdio: 'ignore'});
const ethers = require('ethers');
const eventSig = "TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)";
const hash = ethers.utils.id(eventSig);
console.log(`Correct keccak256 hash: ${hash}`);
EOFRepository: RequestNetwork/requestNetwork
Length of output: 821
🏁 Script executed:
# Alternative: try using eth-hash library via Python
python3 << 'EOF'
import subprocess
import sys
try:
# Try to calculate using a different method
# Let's use OpenSSL or a manual calculation
subprocess.run([sys.executable, "-m", "pip", "install", "eth-hash", "pycryptodome", "-q"])
from eth_hash.auto import keccak
event_sig = "TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)"
keccak_hash = keccak(text=event_sig)
print(f"Correct keccak256 hash: {keccak_hash.hex()}")
except Exception as e:
print(f"Error: {e}")
EOFRepository: RequestNetwork/requestNetwork
Length of output: 142
🏁 Script executed:
# Let me search for test files that might reference the correct hash
rg -n "TransferWithReferenceAndFee" packages/smart-contracts/test/tron/ -A 5 -B 5Repository: RequestNetwork/requestNetwork
Length of output: 1237
🏁 Script executed:
# Check if there are any other references to event topics or signatures in TRON files
rg -n "topic\|event.*hash" packages/substreams-tron/ -iRepository: RequestNetwork/requestNetwork
Length of output: 55
🏁 Script executed:
# Verify the constant TRANSFER_WITH_REF_AND_FEE_TOPIC is never used anywhere
rg "TRANSFER_WITH_REF_AND_FEE_TOPIC" --no-headingRepository: RequestNetwork/requestNetwork
Length of output: 154
🏁 Script executed:
# Check the entire lib.rs file to confirm there's no validation logic later
cat packages/substreams-tron/src/lib.rs | wc -lRepository: RequestNetwork/requestNetwork
Length of output: 76
🏁 Script executed:
# Read the entire file to ensure we haven't missed anything
tail -100 packages/substreams-tron/src/lib.rsRepository: RequestNetwork/requestNetwork
Length of output: 3383
🏁 Script executed:
# Let's try to verify the keccak256 hash by checking test files or documentation
rg -n "0x" packages/substreams-tron/ --type rust -B2 -A2 | head -50Repository: RequestNetwork/requestNetwork
Length of output: 1474
🏁 Script executed:
# Check if there's a README or documentation about the event signature
cat packages/substreams-tron/README.mdRepository: RequestNetwork/requestNetwork
Length of output: 2149
Add event signature validation to prevent incorrect event processing.
TRANSFER_WITH_REF_AND_FEE_TOPIC is defined but never used. The code at lines 45-47 only checks if topics.is_empty() but doesn't validate that topics[0] matches the expected event signature. This means all events from the proxy contracts will be parsed as TransferWithReferenceAndFee events, causing incorrect data or parsing failures.
Additionally, the topic constant is truncated (40 hex chars = 20 bytes vs. 64 hex chars = 32 bytes expected for keccak256).
Add validation before parsing:
Proposed fix
// Check if this is a TransferWithReferenceAndFee event
// The first topic should be the event signature
if log_entry.topics.is_empty() {
continue;
}
+ // Validate event signature
+ let event_sig = hex::encode(&log_entry.topics[0]);
+ if event_sig != TRANSFER_WITH_REF_AND_FEE_TOPIC {
+ continue;
+ }
+
// Parse the event data🤖 Prompt for AI Agents
In `@packages/substreams-tron/src/lib.rs` around lines 17 - 47, The
map_erc20_fee_proxy_payments handler currently skips only empty topics and never
validates the event signature; update it to first ensure log_entry.topics[0]
exists and matches the expected keccak256 event signature by comparing a
normalized hex string of log_entry.topics[0] to a corrected
TRANSFER_WITH_REF_AND_FEE_TOPIC constant (replace the truncated 40-hex-char
value with the full 64-hex-char keccak256 hash and use lowercase/no-0x
normalization), and only proceed parsing when they match; reference
TRANSFER_WITH_REF_AND_FEE_TOPIC, map_erc20_fee_proxy_payments, and
log_entry.topics for where to add this check.
✅ Slither Security AnalysisStatus: Passed Findings Summary
📄 Full report available in workflow artifacts. |
✅ Echidna Fuzzing ResultsMode: ci (50000 test sequences) Property Test Results
📄 Full report and corpus available in workflow artifacts. ℹ️ About Echidna FuzzingEchidna is a property-based fuzzer that generates random sequences of transactions Properties tested:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/payment-processor/src/payment/utils-tron.ts`:
- Around line 153-166: The code currently returns the txid from
contract.approve(...).send() without checking on-chain execution; after
receiving result in approveTrc20 (and similarly in processTronFeeProxyPayment)
call tronWeb.trx.getTransactionInfo(txHash) and inspect
contractInfo.contractResult — if contractResult exists and contains any entry
not equal to 'SUCCESS' (or indicates an error payload), treat it as a failed
transaction: call callback?.onError with a descriptive Error including the
contractResult/receipt details and throw an Error instead of returning the txid;
only call callback?.onHash and return the txid when the on-chain contractResult
shows success. Ensure you reference the txHash derived from result.txid ||
result.transaction?.txID and use tronWeb.trx.getTransactionInfo(txHash) to
validate.
♻️ Duplicate comments (4)
packages/substreams-tron/src/lib.rs (1)
17-47: Blocker: validate event signature and fix truncated topic hash before parsing.Right now only
topics.is_empty()is checked, so non‑TransferWithReferenceAndFee logs from the proxy contract can be parsed as payments. Also the topic constant is only 20 bytes (40 hex chars), not a full keccak256 topic. Add atopics[0]signature check and update the constant to the full 32‑byte hash derived from the event signature.Suggested fix
const TRANSFER_WITH_REF_AND_FEE_TOPIC: &str = - "e8e8ca0a945b88ee72ec3e1e5f1e9c8f2a0a1e8a"; + "<full 64-hex keccak256 of TransferWithReferenceAndFee(address,address,uint256,bytes,uint256,address)>"; ... if log_entry.topics.is_empty() { continue; } + // Validate event signature + if hex::encode(&log_entry.topics[0]) != TRANSFER_WITH_REF_AND_FEE_TOPIC { + continue; + }packages/smart-contracts/scripts/tron/deploy-mainnet.js (1)
167-168: Deployment manifest output path appears incorrect.The path resolves to
packages/smart-contracts/scripts/deployments/mainnet.jsoninstead of the canonicalpackages/smart-contracts/deployments/tron/mainnet.json. This was flagged in a previous review and marked as addressed—verify the fix was applied.packages/smart-contracts/scripts/tron/deploy-nile.js (1)
133-135: Fix deployment output path to tron/deployments.
Line 133 writes toscripts/deployments, but tooling expectstron/deployments. This will misplace Nile artifacts.🛠️ Proposed fix
- const outputPath = path.join(__dirname, '../deployments/nile.json'); + const outputPath = path.join(__dirname, '../../tron/deployments/nile.json');packages/smart-contracts/scripts/tron/deploy-test-token.js (1)
107-109: Write deployment JSON under tron/deployments.
Line 107 currently writes toscripts/deployments, which is not where Tron deployment tooling reads from.🛠️ Proposed fix
- const outputPath = path.join(__dirname, '../deployments/nile-test-token.json'); + const outputPath = path.join(__dirname, '../../tron/deployments/nile-test-token.json');
| try { | ||
| const result = await contract.approve(proxyAddress, amount.toString()).send({ | ||
| feeLimit: 100000000, // 100 TRX fee limit | ||
| shouldPollResponse: true, | ||
| }); | ||
|
|
||
| const txHash = result.txid || result.transaction?.txID || ''; | ||
| callback?.onHash?.(txHash); | ||
|
|
||
| return txHash; | ||
| } catch (error) { | ||
| callback?.onError?.(error as Error); | ||
| throw new Error(`TRC20 approval failed: ${(error as Error).message}`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
TronWeb v6 contract send() method error handling revert behavior
💡 Result:
Short answer
- TronWeb v6’s contract method send() will submit the transaction and return the transaction id / RPC response; if the TVM reverts the call the chain still records a failed (reverted) transaction — state is rolled back but energy/fees are consumed. TronWeb does not automatically surface a Solidity revert string for you. [1][2][3]
How to get the revert reason (practical steps)
- Submit the tx with tronWeb and get the txid (send()).
- Query transaction info (wallet/gettransactioninfobyid or tronWeb.trx.getTransactionInfo(txid)). Inspect the contractResult field in the response — it will contain the ABI-encoded revert payload (hex). [3][4]
- Decode the hex payload (it follows the ABI error encoding, e.g. 0x08c379a0 + string length + bytes) to get the human-readable revert string. The TRON docs show the same workflow and example. [3][4]
Common causes to check before decoding
- Out of Energy / insufficient fee_limit (common cause of failure).
- Require/assert or explicit revert in contract logic. [2][3]
References
- TronWeb v6 release / repo (context on v6 behavior and issues). [1]
- TRON VM exception handling (revert semantics, energy/fee effects). [2]
- TRON FAQ / wallet/gettransactioninfobyid example showing contractResult decoding to obtain revert text. [3]
- TronWeb GitHub issue about CONTRACT_VALIDATE_ERROR (example of error payloads and need to decode). [4]
If you want, tell me the txid and I can fetch and decode the contractResult for you.
🏁 Script executed:
# Find and examine the utils-tron.ts file to understand context
fd -t f "utils-tron.ts" --exec wc -l {} \;Repository: RequestNetwork/requestNetwork
Length of output: 131
🏁 Script executed:
# Read the specific sections mentioned in the review
cat -n packages/payment-processor/src/payment/utils-tron.ts | sed -n '145,235p'Repository: RequestNetwork/requestNetwork
Length of output: 3351
🏁 Script executed:
# Search for other TronWeb .send() usages in the codebase to see patterns
rg "\.send\(" --type ts -A 5 -B 2 packages/payment-processor/Repository: RequestNetwork/requestNetwork
Length of output: 3122
Add transaction success validation for TronWeb contract calls
In approveTrc20 and processTronFeeProxyPayment, .send() returns a transaction ID even when the transaction reverts on-chain. The code returns the txid without validating success, so callers will treat failed approvals/payments as successful.
After receiving the result from .send(), query the transaction info using tronWeb.trx.getTransactionInfo(txid) and inspect the contractResult field. If contractResult indicates failure (non-empty error payload), throw an error instead of returning the txid. Otherwise, silent transaction failures will cause subsequent operations to fail.
🤖 Prompt for AI Agents
In `@packages/payment-processor/src/payment/utils-tron.ts` around lines 153 - 166,
The code currently returns the txid from contract.approve(...).send() without
checking on-chain execution; after receiving result in approveTrc20 (and
similarly in processTronFeeProxyPayment) call
tronWeb.trx.getTransactionInfo(txHash) and inspect contractInfo.contractResult —
if contractResult exists and contains any entry not equal to 'SUCCESS' (or
indicates an error payload), treat it as a failed transaction: call
callback?.onError with a descriptive Error including the contractResult/receipt
details and throw an Error instead of returning the txid; only call
callback?.onHash and return the txid when the on-chain contractResult shows
success. Ensure you reference the txHash derived from result.txid ||
result.transaction?.txID and use tronWeb.trx.getTransactionInfo(txHash) to
validate.

Add Tron Blockchain Support for Smart Contracts and Payment Processor
Summary
This PR adds comprehensive Tron blockchain support to Request Network, enabling TRC20 token payments through the
ERC20FeeProxycontract. The implementation includes smart contract deployment infrastructure, a new payment processor module, and a complete test suite to ensure feature parity with EVM chains.Problem Statement
No payment proxy contract existed on Tron, blocking all payment functionality for Tron users. This PR resolves this by deploying the
ERC20FeeProxycontract adapted for TRC20 tokens.Changes
Smart Contracts (
packages/smart-contracts)tronbox-config.jswith support for local development, Nile testnet, and mainnettron/contracts/directory with Solidity contracts compiled for Tron (solc 0.8.6)TestTRC20,BadTRC20,TRC20True,TRC20NoReturn,TRC20False,TRC20Revertfor comprehensive testingdeploy-nile.js- Deploy to Nile testnetdeploy-mainnet.js- Deploy to Tron mainnet (with safety confirmations)verify-deployment.js- Verify deployed contractssetup-test-wallet.js- Helper for test wallet setupERC20FeeProxyartifact with Tron deployment addresses:THK5rNmrvCujhmrXa5DB1dASepwXTr9cJsTCUDPYnS9dH3WvFEaE7wN7vnDa51J4R4fdPayment Processor (
packages/payment-processor)utils-tron.ts: TronWeb utilities for address validation, balance/allowance checks, and contract interactionstron-fee-proxy.ts: Payment functions for Tron:payTronFeeProxyRequest()- Execute TRC20 paymentsapproveTronFeeProxyRequest()- Approve token spendinghasSufficientTronAllowance()- Check allowancehasSufficientTronBalance()- Check balancegetTronPaymentInfo()- Get payment details from requestCurrency Package (
packages/currency)TronChainsclass for Tron chain utilitiesniletestnet chain definitiontronchain with TRC20 token informationTypes Package (
packages/types)TronChainNameto include'tron' | 'nile'VMChainNameto include Tron chainsCI/CD (
.github/workflows)tron-smart-contracts.yml: New workflow for Tron contract compilation and testingtronbox/treDocker image for local testingTest Coverage
Smart Contract Tests (
tron/test/ERC20FeeProxy.test.js)13 test cases matching EVM test coverage:
Payment Processor Tests (
test/payment/tron-fee-proxy.test.ts)21 unit tests covering:
New npm Scripts
yarn tron:compile # Compile Tron contracts
yarn tron:test # Run tests on local TRE
yarn tron:deploy:nile # Deploy to Nile testnet
yarn tron:deploy:mainnet # Deploy to mainnet
yarn tron:verify:nile # Verify Nile deployment
yarn tron:verify:mainnet # Verify mainnet deployment
yarn tron:setup-wallet # Setup test wallet
yarn tron:deploy:test-token # Deploy test token to Nile
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.